// 构造自己的智能指针
// 用一个 enum 来处理：当字符串小于 N 字节时，直接用栈上的数组，否则，使用 String。

/*
使用 enum 时，额外的 tag + 为了对齐而使用的 padding 会占用一些内存。
因为 String 结构是 8 字节对齐的，所以的 enum 最小 8 + 24 = 32 个字节。
*/

use std::{fmt, ops::Deref, str};

const MAX_STRING_LEN: usize = 30;
struct MiniString {
    len: u8,
    data: [u8; MAX_STRING_LEN],
}

impl MiniString {
    //  new 方法不暴露出去，自行保证传入的 v 的字节长度小于等于 30
    fn new(v: impl AsRef<str>) -> Self {
        let bytes = v.as_ref().as_bytes();
        let len = bytes.len(); // 长度注意使用bytes的长度
        let mut data = [0u8; MAX_STRING_LEN];
        data[..len].copy_from_slice(bytes);
        Self {
            len: len as u8,
            data: data,
        }
    }
}

// 为了方便处理需要实现解引用（MiniString -> &str）
impl Deref for MiniString {
    type Target = str;
    fn deref(&self) -> &Self::Target {
        str::from_utf8(&self.data[..self.len as usize]).unwrap()
        // 因为MiniString非导出，这里self一定是str，所以这个操作是安全的
        // 也可以直接用 unsafe 版本
        // unsafe { str::from_utf8_unchecked(&self.data[..self.len as usize]) }
    }
}

impl fmt::Debug for MiniString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.deref()) // 因为实现了Deref，可以直接得到str的输出
    }
}

#[derive(Debug)]
enum MyString {
    // 实现两种分发
    Inline(MiniString),
    Standard(String),
}

// 这是针对MyString的Deref，可以将两种结构都转化为&str
impl Deref for MyString {
    type Target = str; // 解引用到str上
    fn deref(&self) -> &Self::Target {
        match *self {
            MyString::Inline(ref v) => v.deref(),
            MyString::Standard(ref v) => v.deref(),
        }
    }
}

// 从&str中获取内容成为MyString
// 因为已经为MyString做了enum的两种分发，所以这里检查&str然后决定MyString应该实现哪个
// 按照设计思路，长度小的作为MiniString，如果长度大于限制，应该作为String
impl From<&str> for MyString {
    fn from(value: &str) -> Self {
        match value.len() > MAX_STRING_LEN {
            true => Self::Standard(value.to_owned()), // 如果长度超过，则按照标准情况，作为Cow(也就是String展示)
            _ => Self::Inline(MiniString::new(value)),
        }
    }
}

impl fmt::Display for MyString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.deref())
    }
}

fn main() {
    let len1 = std::mem::size_of::<MyString>();
    let len2 = std::mem::size_of::<MiniString>();
    println!("len: MyString {} ; MiniString {}", len1, len2);
    let s1: MyString = "hello world".into();
    let s2: MyString =
        "inudhasiufdsiufndsuifdsuifdusifhuidnfiudsnfuidsbfsdhfudshnfiudsnfdhsfuidhuf".into();

    println!("s1 {:?} , s2 {:?}", s1, s2);
    println!(
        "s1: {} ({} bytes,{} char ); s2: {} ({} bytes , {} chars)",
        s1,
        s1.len(),
        s1.chars().count(),
        s2,
        s2.len(),
        s2.chars().count()
    );

    assert!(s1.ends_with("world"));
    assert!(s2.starts_with("inud"));
}
